`timescale  1ns/1ns

module  rs232
(
    input   wire    sys_clk     ,    //系统时钟50MHz
    input   wire    sys_rst_n   ,   //全局复位
    input   wire    rx          ,   //串口接收数据
    
    output  wire    tx              //串口发送数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   UART_BPS    =   20'd9600        ,   //比特率
            CLK_FREQ    =   26'd50_000_000  ;   //时钟频率

localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;
//wire  define
wire            en_h_flag;
wire    [7:0]   po_data;    //接收的数据
wire            po_flag;    //接收完1字节数据标志位,高电平有效
wire            flag;       //识别到接收数据与密码对应标志位
wire            tx_flag;    //发送完1字节数据标志位,高电平有效
reg     [39:0]  datain_reg; //存储接收的数据,5字节
reg     [47:0]  dataout_reg;//存储的要发送的数据,6字节
reg     [1:0]   state;      //状态位
reg     [7:0]   data_tx;    //发送的1字节数据
reg             en_tx;      //发送允许标志位
reg     [2:0]   tx_cnt;     //发送字节计数器,发送6个后置0
reg             en;         //发送控制开关
reg     [12:0]  baud_cnt;   //收到发送成功的tx_flag后延迟1个波特
reg             bit_flag;   //计满1baud有效
reg             work;       //波特计数器baud_cnt有效
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------ uart_rx_inst ------------------------
uart_rx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_rx_inst
(
    .sys_clk    (sys_clk    ),  //input             sys_clk
    .sys_rst_n  (sys_rst_n  ),  //input             sys_rst_n
    .rx         (rx         ),  //input             rx
            
    .po_data    (po_data    ),  //output    [7:0]   po_data
    .po_flag    (po_flag    )   //output            po_flag
);
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        en <= 1'b1;
    else if(en_h_flag)
        en <= 1'b1;
    else if(tx_cnt>=3'd5)
        en <= 1'b0;   
//接收数据寄存
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        datain_reg <= 40'd0;
    else if(po_flag)
        datain_reg <= {datain_reg[31:0],po_data[7:0]};
        
//接收到tx_flag后,延迟一个baud时间再发送下一个
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        work <= 1'b0;
    else if(tx_flag)
        work <= 1'b1;
    else if(state != 2'd2)
        work <= 1'b0;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        baud_cnt <= 13'd0;
    else if((baud_cnt == BAUD_CNT_MAX - 1) || en_tx)
        baud_cnt <= 13'b0;
    else if(work)
        baud_cnt <= baud_cnt + 1'd1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        bit_flag <= 1'b0;
    else if(baud_cnt == BAUD_CNT_MAX - 1)
        bit_flag <= 1'b1;
    else if(state != 2'd2) 
        bit_flag <= 1'b0;

                              //hello的ASCII码
assign flag = (datain_reg == 40'h68656c6c6f)? 1'b1:1'b0;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        begin
            state <= 2'd0;
            dataout_reg <= 48'h6e692c68616f;//ni,hao的ASCII码
            data_tx <= 8'd0;
            en_tx <= 1'b0;
            tx_cnt <= 3'd0;
        end
    else
        case(state)
            2'd0:
                begin
                    if(flag && en)
                        state <= 2'd1;
                    else
                        state <= 2'd0;
                end
            2'd1://发送数据
                begin
                    state <= 2'd2;
                    data_tx <= dataout_reg[47:40];
                    en_tx <= 1'b1;
                    dataout_reg <= dataout_reg << 8;
                end            
            2'd2://等待数据发送完成,并计数+1
                begin
                    if(bit_flag)
                        begin
                            if(tx_cnt>=3'd5)begin
                                state <= 2'd0;
                                tx_cnt <= 3'd0;                         
                            end
                            else begin
                                state <= 2'd1;
                                tx_cnt <= tx_cnt + 1'd1;                            
                            end 
                        end
                    else
                        begin
                            en_tx <= 1'b0;
                            state <= 2'd2;
                        end
                end 
            default : state <= 2'd0;
        endcase            
//------------------------ uart_tx_inst ------------------------
uart_tx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_tx_inst
(
    .sys_clk    (sys_clk    ),  
    .sys_rst_n  (sys_rst_n  ),  
    .pi_data    (data_tx    ),  
    .pi_flag    (en_tx      ),     
    
    .tx         (tx         ),   
    .tx_flag    (tx_flag    )
);

endmodule

